#pragma once

#include <new>           
#include <assert.h>

#define CORE_EXPANSION_SIZE 1024

template< class T, int nObjects = CORE_EXPANSION_SIZE >
class MemoryPool {
public:
   MemoryPool() : head( NULL ) {}

   void* allocate();
   void free(void* p);

  
private:
   struct Thunk { 
      T object;
      Thunk* next;
   };

private:
   Thunk* head; // next available block in the pool
};

template< class T, int nObjects >
void* MemoryPool< T, nObjects >::allocate() {
   if ( head == NULL ) { // if no more memory in the pool
      

      // use the global operator new to allocate a block for the pool
      Thunk* pool = reinterpret_cast<Thunk*>(::operator new(nObjects * sizeof(Thunk)));

      // initialize the chain (one-directional linked list)
      head = pool;
	  const int last = nObjects - 1;
      for (int i = 0; i < last; ++i ) {
			pool[i].next = &pool[i+1];
      }
      pool[last].next = NULL;
   }

   // set head to point to the next object in the list
   Thunk* currentThunk = head;
   head = currentThunk->next;

   return currentThunk;
}

template< class T, int nObjects >
void MemoryPool< T, nObjects >::free(void* t) {
   assert(t != NULL);     
   if (t == NULL) return; // for safety

   // recycle the object memory, by putting it back into the chain
   reinterpret_cast<Thunk*>(t)->next = head;
   head = reinterpret_cast<Thunk*>(t);
}
